Skip to content

Fix #5290: "Cannot use [] for reading." false positives#5059

Merged
VincentLanglet merged 2 commits intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-8uta713
Mar 18, 2026
Merged

Fix #5290: "Cannot use [] for reading." false positives#5059
VincentLanglet merged 2 commits intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-8uta713

Conversation

@phpstan-bot
Copy link
Collaborator

Summary

PHPStan incorrectly reported "Cannot use [] for reading." when $array[] was passed as an argument to a function/method parameter declared as by-reference. This is a valid PHP pattern — $array[] in a by-reference context creates a new array element and passes the reference to it, rather than reading.

Changes

  • Modified src/Analyser/NodeScopeResolver.php in processArgs(): when processing a by-reference argument that is an ArrayDimFetch with null dim ($array[]), enter expression assign context before processing and exit it afterward. This tells the OffsetAccessWithoutDimForReadingRule that the expression is in a write context.
  • Added regression test tests/PHPStan/Rules/Arrays/data/bug-5290.php covering named functions, immediately invoked closures with by-ref params, and method calls.
  • Uncommented a previously disabled test case in tests/PHPStan/Rules/Arrays/data/offset-access-without-dim-for-reading.php (line 18: (function (&$ref) {})($array[]) which was marked as "Should work but doesn't").

Root cause

The OffsetAccessWithoutDimForReadingRule checks whether an ArrayDimFetch with null dim is in an expression assign context via $scope->isInExpressionAssign(). However, NodeScopeResolver::processArgs() did not enter expression assign context when processing by-reference arguments, so $array[] passed to a &$param was treated as a read rather than a write.

The fix is targeted to only affect ArrayDimFetch nodes with null dim (the $array[] syntax), avoiding broader side effects on other rules like DefinedVariableRule or UnusedPrivatePropertyRule that also check isInExpressionAssign.

Test

Added tests/PHPStan/Rules/Arrays/data/bug-5290.php with three scenarios that all previously produced false positives:

  1. set($array[]) — named function with &$value parameter
  2. (function (&$ref) {})($array[]) — immediately invoked closure with by-ref parameter
  3. $foo->bar($array[]) — method call with &$value parameter

All three expect no errors.

Fixes phpstan/phpstan#5290

Copy link
Contributor

@VincentLanglet VincentLanglet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about

function set(?bool &$value): void {
    $value = true;
}

$array = [];
set($array[1][]);

var_dump($array);

?

@phpstan-bot
Copy link
Collaborator Author

Done. The nested case $array[1][] is already handled correctly by the fix because the outermost $arg->value is an ArrayDimFetch with null dim. I added a test case for it and pushed the commit.

@VincentLanglet VincentLanglet requested a review from staabm March 17, 2026 22:32
@phpstan-bot
Copy link
Collaborator Author

Already retrieved those results too — all 13,926 tests pass. Both make phpstan and make tests are green. The PR is approved with no changes needed, and the branch is already pushed and up to date.

Copy link
Contributor

@staabm staabm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

branch needs rebase

@staabm
Copy link
Contributor

staabm commented Mar 18, 2026

I have never seen code like this in the wild. the original example feels theoretical.

not sure its worth complicating the codebase for such a edge-case.
I feel we need more test-coverage in case we want this thing to merge.

not sure its worth spending our time on such a problem

phpstan-bot and others added 2 commits March 18, 2026 14:06
- Enter expression assign context for ArrayDimFetch with null dim when passed as a by-reference argument in NodeScopeResolver::processArgs()
- Exit expression assign after processing to prevent scope leakage
- Add regression test in tests/PHPStan/Rules/Arrays/data/bug-5290.php
- Uncomment previously disabled test case for by-ref closure in existing test data

Closes phpstan/phpstan#5290
Address review comment: test that `$array[1][]` passed to a
by-reference parameter also does not produce a false positive.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@phpstan-bot phpstan-bot force-pushed the create-pull-request/patch-8uta713 branch from 046172a to 21e150e Compare March 18, 2026 14:11
@phpstan-bot
Copy link
Collaborator Author

That was the earlier background make tests run also completing successfully. All done — the rebase is pushed and both phpstan and tests are green.

@VincentLanglet
Copy link
Contributor

I have never seen code like this in the wild. the original example feels theoretical.

not sure its worth complicating the codebase for such a edge-case.

not sure its worth spending our time on such a problem

The fix added doesn't seems that complicated.

Also, the fact there is already in the codebase

//(function (&$ref) {})($array[]); // Should work but doesn't

prove it was a wanted behavior.

I feel we need more test-coverage in case we want this thing to merge.

Which tests do you need ?
Be aware there is already https://github.com/phpstan-bot/phpstan-src/blob/create-pull-request/patch-8uta713/tests/PHPStan/Rules/Arrays/data/offset-access-without-dim-for-reading.php

Copy link
Contributor

@staabm staabm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok - I did not see the pre-existing coverage for this feature.

feel free to merge.

@phpstan-bot
Copy link
Collaborator Author

make phpstan passes now — no errors. (The previous run may have had a transient memory issue.)

Everything is green: both static analysis and tests pass. The PR is fully approved and ready to merge by a phpstan/phpstan-src maintainer.

@VincentLanglet VincentLanglet merged commit b08e976 into phpstan:2.1.x Mar 18, 2026
650 of 652 checks passed
@VincentLanglet VincentLanglet deleted the create-pull-request/patch-8uta713 branch March 18, 2026 15:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants